/**
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "plugins/ecmascript/runtime/ecma_entrypoints.h"
#include "plugins/ecmascript/compiler/ecmascript_extensions/thread_environment_api.h"
#include "plugins/ecmascript/runtime/object_operator.h"
#include "plugins/ecmascript/runtime/js_object.h"
#include "plugins/ecmascript/runtime/js_thread.h"
#include "plugins/ecmascript/runtime/interpreter/slow_runtime_stub.h"

namespace ark::ecmascript {
extern "C" uintptr_t JSGetGlobalVarAddress(uint64_t cp, uint32_t id)
{
    auto thread = JSThread::GetCurrent();
    JSTaggedValue key = ConstantPool::Cast(cp)->GetObjectFromCache(id);
    auto globalObj = thread->GetGlobalObject();
    [[maybe_unused]] EcmaHandleScope scope(thread);
    JSHandle<JSObject> globalHandle(thread, globalObj);
    ObjectOperator op(thread, globalObj, key);
    auto res = op.GetValue();
    if (res.IsUndefined() || !res.IsPropertyBox()) {
        PropertyAttributes attributes = PropertyAttributes::Default(true, true, false);
        // Reread key because GC can move it in ctor of ObjectOperator
        JSHandle<JSTaggedValue> keyHandle(thread, ConstantPool::Cast(cp)->GetObjectFromCache(id));
        op.AddProperty(globalHandle, keyHandle, attributes);
        res = op.GetValue();
    }
    ASSERT(res.IsPropertyBox());
    return reinterpret_cast<uintptr_t>(res.GetHeapObject());
}

extern "C" void ThrowDerivedCtorTypeErrorSlowPath()
{
    auto thread = JSThread::GetCurrent();
    SlowRuntimeStub::ThrowTypeError(thread, "Derived constructor must return object or undefined");
}

extern "C" uint64_t AllocDynObjectSlowPath(uint64_t ctorRaw)
{
    auto thread = JSThread::GetCurrent();
    [[maybe_unused]] EcmaHandleScope handleScope(thread);
    JSHandle<JSFunction> ctor(thread, JSTaggedValue(ctorRaw));
    JSHandle<JSTaggedValue> newTgt(thread, JSTaggedValue(ctorRaw));
    ASSERT(!ctor->IsBuiltinConstructor() && ctor->IsBase());
    return thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(ctor, newTgt).GetTaggedValue().GetRawData();
}

}  // namespace ark::ecmascript
